/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2022 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "iwdg.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "setting.h"
#include "flash.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */


/**
 * @brief 屏幕刷新进程计时队列
 */
MONO_PriorityTimerQueue *tim3_queue = NULL;

/**
 * @brief 用于驱动BLUZZER
 */
MONO_PriorityTimerQueue *tim1_queue = NULL;

/**
 * @brief 测温 加热
 */
MONO_PriorityTimerQueue *power_process_queue = NULL;

/**
 * @brief 更新UI的模式
 */
volatile uint32_t g_updateUi = UPDATE_UI_ALL;

/**
 * @brief 升温PID 猛烈的
 */
PID_STRUCTURE *g_pidStructurePower = NULL;

/**
 * @brief  回温PID 敌不动我不动
 */
PID_STRUCTURE *g_pidStructureBack = NULL;

/**
 * @brief 错误标志，如果为1，则运行
 */
uint8_t g_errorFlag = 0;

/**
 * @brief error type
 */
ERROR_TYPE g_errorType;

/**
 * @brief 设定温度
 */
volatile uint16_t g_settingTemperaturePowerValue = 280;

/**
 * @brief 该值为旋转一次触发前进步数
 */
uint16_t g_settingTemperatureStepValue = 10;

/**
 * @brief 现在的温度
 */
volatile uint16_t g_nowTemperatureValue = 0;

/**
 * @brief 当前的ADC电压值
 */
volatile double g_nowAdcVoltValue = 0;

/**
 * @brief 当前ADC读到的值
 */
volatile uint32_t g_nowAdcValue = 0;

/**
 * @brief 输入状态分为可调整状态和非调整状态
 * 1为不可调整状态
 */
volatile uint8_t g_inputStatus = 0;

/**
 * @brief pid算出来的加热的油门
 */
volatile double g_pidPowerValue;

/**
 * @brief 基准温度与adc的比率
 */
const double g_identifyHotRate = IDENTIFY_ADC / IDENTIFY_TEMPERATURE;

/**
 * @brief 休眠计时器
 */
volatile uint32_t sleep_Timer = 0;

/**
 * @brief 保存设置的结构体
 */
SETTING_STRUCTURE *g_settings;

volatile uint8_t waitStatus = 0;

volatile uint8_t stepWaitStatus = 0;




/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (hadc == &hadc1)
    {
        HAL_ADC_Stop_IT(&hadc1);
    g_nowAdcValue = HAL_ADC_GetValue(&hadc1);
        g_nowAdcVoltValue = (g_nowAdcValue * 3.3) / 4096;
        HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
    }
}

// // 消抖状态
// volatile uint8_t tick_status = 0;
// // 消抖计时器
// volatile uint16_t tick_timer = 0;

// // 避免多次触发
// volatile uint8_t stop_status = 0;
// // 避免多次触发的计时器
// volatile uint8_t stop_timer = 0;

/**
 * @brief 清除按下标记
 */
static void ClearWaitStatus()
{
    waitStatus = 0;
}

/**
 * @brief 清除按下标记
 */
static void ClearStepStatus()
{
    stepWaitStatus = 0;
}


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    switch (GPIO_Pin)
    {
    case ENC_A_Pin:
        if (stepWaitStatus == 1)
        {
            break;
        }
        if (HAL_GPIO_ReadPin(ENC_B_GPIO_Port, ENC_B_Pin) == GPIO_PIN_RESET)
        {
            if (g_inputStatus == 1)
            {
                g_updateUi |= (0x01 << UPDATE_UI_SETTING_TEMPERATURE);
                if (g_settingTemperaturePowerValue > MIN_TEMPERATURE)
                {
                    if (g_settingTemperaturePowerValue - g_settingTemperatureStepValue < MIN_TEMPERATURE)
                    {
                        g_settingTemperaturePowerValue = MIN_TEMPERATURE;
                    }
                    else
                    {
                        g_settingTemperaturePowerValue -= g_settingTemperatureStepValue;
                    }
                }
            }

            stepWaitStatus = 1;
            // 创建屏幕刷新任务
            MONO_PriorityTimerNode *clearEncoderStatusNode =
                MONO__CreateQueueNode((MONO_NodeFunction_t)&ClearStepStatus, 0, 1, 311, 0, 0, 3, NULL, NULL);
            MONO_PushNode(tim1_queue, clearEncoderStatusNode);

        }
        break;
    case ENC_B_Pin:
        if (stepWaitStatus == 1)
        {
            break;
        }
        if (HAL_GPIO_ReadPin(ENC_A_GPIO_Port, ENC_A_Pin) == GPIO_PIN_RESET)
        {
            if (g_inputStatus == 1)
            {
                g_updateUi |= (0x01 << UPDATE_UI_SETTING_TEMPERATURE);
                if (g_settingTemperaturePowerValue < MAX_TEMPERATURE)
                {
                    if (g_settingTemperaturePowerValue + g_settingTemperatureStepValue > MAX_TEMPERATURE)
                    {
                        g_settingTemperaturePowerValue = MAX_TEMPERATURE;
                    }
                    else
                    {
                        g_settingTemperaturePowerValue += g_settingTemperatureStepValue;
                    }
                }
            }

            stepWaitStatus = 1;
            // 创建屏幕刷新任务
            MONO_PriorityTimerNode *clearEncoderStatusNode =
                MONO__CreateQueueNode((MONO_NodeFunction_t)&ClearStepStatus, 0, 1, 311, 0, 0, 1, NULL, NULL);
            MONO_PushNode(tim1_queue, clearEncoderStatusNode);

        }
        break;
    case ENC_SW_Pin:
        if (waitStatus == 0)
        {
            if (g_inputStatus == 0)
            {
                // 开启外部中断
                // 关闭定时器与pwm
                HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
                // HAL_TIM_Base_Stop_IT(&htim3);
                HAL_TIM_Base_Stop_IT(&htim4);
                HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_4);
                g_inputStatus = 1;
            }
            else
            {
                HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
                HAL_TIM_Base_Start_IT(&htim4);
                g_inputStatus = 0;
            }
            // tick_timer = 0;
            g_updateUi |= (0x01 << UPDATE_UI_SETTING_STATUS);

            waitStatus = 1;
            // 创建屏幕刷新任务
            MONO_PriorityTimerNode *clearWaitStatusNode =
                MONO__CreateQueueNode((MONO_NodeFunction_t)&ClearWaitStatus, 0, 1, 61, 0, 0, 2, NULL, NULL);
            MONO_PushNode(tim3_queue, clearWaitStatusNode);
        }
        break;
    default:
        break;
    }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == &htim1)
    {
        // run tim1_queue priority timer counter
        MONO_TimerRunning(tim1_queue);
        // run inner timer node
        MONO_RunInnerTimerNode(tim1_queue);
    }
    else if (htim == &htim3)
    {
        // run tim3_queue priority timer counter
        MONO_TimerRunning(tim3_queue);
        // run inner timer node
        MONO_RunInnerTimerNode(tim3_queue);
    }
    else if (htim == &htim4)
    {
        // run power_process_queue priority timer counter
        MONO_TimerRunning(power_process_queue);
        // run inner timer node
        MONO_RunInnerTimerNode(power_process_queue);
    }
}

/**
 * @brief 初始化PID
 */
void initPid()
{
    if (g_pidStructurePower != NULL)
    {
        free(g_pidStructurePower);
        g_pidStructurePower = NULL;
    }

    if (g_pidStructureBack != NULL)
    {
        free(g_pidStructureBack);
        g_pidStructureBack = NULL;
    }

    g_pidStructurePower       = (PID_STRUCTURE *)calloc(1, sizeof(PID_STRUCTURE));
    g_pidStructurePower->_P   = 30;
    g_pidStructurePower->_I   = 0;
    g_pidStructurePower->_D   = 80;
    g_pidStructurePower->_dt  = 1;
    g_pidStructurePower->_max = 4096;
    g_pidStructurePower->_min = 0;

    g_pidStructureBack       = (PID_STRUCTURE *)calloc(1, sizeof(PID_STRUCTURE));
    g_pidStructureBack->_P   = 14;
    g_pidStructureBack->_I   = 2;
    g_pidStructureBack->_D   = 30;
    g_pidStructureBack->_dt  = 1;
    g_pidStructureBack->_max = 4096;
    g_pidStructureBack->_min = 0;
}

void T12_Init()
{
    initPid();

    initProcesses();

    if (g_settings != NULL)
    {
        free(g_settings);
        g_settings = NULL;
    }
    g_settings = (SETTING_STRUCTURE *)calloc(1, sizeof(SETTING_STRUCTURE));
    #ifndef REFLASH_DATA

    Flash_ReadData(DEFAULT_FLASH_START_ADDR, (uint16_t *) g_settings, sizeof(SETTING_STRUCTURE));

    // if (g_settings->setting_temperature > MAX_TEMPERATURE || g_settings->setting_temperature < MIN_TEMPERATURE)
    // {
    //   g_settings->setting_temperature = g_settingTemperaturePowerValue;
    // }

    // if (g_settings->setting_step > 20 || g_settings->setting_step < 0)
    // {
    //   g_settings->setting_step = 10;
    // }

    g_settingTemperatureStepValue = g_settings->setting_step;
    g_settingTemperaturePowerValue = g_settings->setting_temperature;
    #endif

    HAL_ADCEx_Calibration_Start(&hadc1);

    // OLED初始化
    oled_init();

    oled_clear();

    g_updateUi = UPDATE_UI_ALL;

    // 首先关闭旋转编码器中断部分
    HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);

    HAL_TIM_Base_Start_IT(&htim1);
    HAL_TIM_Base_Start_IT(&htim3);
    HAL_TIM_Base_Start_IT(&htim4);
}

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_ADC1_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_IWDG_Init();
  MX_TIM4_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */

    T12_Init();

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
        HAL_IWDG_Refresh(&hiwdg);
        // run timer node.
        MONO_RunTimerNode(tim1_queue);
        MONO_RunTimerNode(tim3_queue);
        MONO_RunTimerNode(power_process_queue);

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
  PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV4;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
